;;; -*- Mode:MIDAS -*- 
;;; Copyright (c) 1999 Massachusetts Institute of Technology
;;;
;;; This program is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation; either version 3 of the
;;; License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program; if not, see https://gnu.org/licenses or
;;; write to:
;;;  Free Software Foundatiom, Inc.
;;;  51 Franklin St, Fifth Floor
;;;  Boston, MA 02110-1301
;;;  USA

SUBTTL	ARPANET HARDWARE DEFINITIONS

IFNDEF BLIMPP,BLIMPP==INETP	; Use IMP blockage avoidance code
IMPVRS==.IFNM2	; Version of IMP/NCP code

IFN KAIMP,[
; Hardware description of AI-KA/ML/MC IMP interface, device "IMP".
; For a more detailed description, see AI Hardware Memo #10,
; "ARPA Network Interface".
; In particular, the "channel 1 multiplexing" feature of the ITS KA's
; is used, so that:
; When PI level 2 (NETCHN) is assigned, the IMP interface takes
;	all interrupts on the normal channel (goes to IMPINT).
; When PI level 1 (IMPCHN) is assigned,
;	IMPID+(-IMPLIW) => Pseudo channel 4, location 70 (IMPILC)-> various
;	IMPOD => Pseudo channel 5, location 72 (IMPOLC)-> various
;	else normal PI channel 1 (PI0LOC+2)-> IMPBRK

; CONI bits - starred items cause interrupt on PIA channel
		; 1.1-1.3 => PIA
IMPID==10	;* INPUT DONE - Turned on when interface has word for DATAI
IMPI32==20	; Input in 32 bit mode
;IMPIB==40	; Input Busy
IMPOD==100	;* OUTPUT DONE - Interface has finished giving word to IMP
;IMPO32==200	; Output in 32 bit mode
;IMPOB==400	; Output Busy
IMPERR==1000	;* Imp Error (interrupt if IMPIC zero)
IMPR==2000	;* Imp Ready (interrupt if IMPIC set)
;IMPIC==4000	; Imp interrupt condition (0 = int on IMPERR, 1= int on IMPR)
IMPHER==10000	;* Host Error (interrupt if IMPIHE zero)
;IMPHR==20000	; Host Ready
;IMPIHE==40000	; Inhibit interrupt on Host Error (IMPHER)
IMPLW==100000	;* Last Imp Word

; CONO bits - starred flags are always copied directly to set states
		;* 1.1-1.3 => PIA set from these bits
IMPIDC==10	; Clear Input Done
IMI32S==20	; Set input to 32 bit mode
IMI32C==40	; Clear input in 32 bit mode
IMPODC==100	; Clear Output Done
IMO32S==200	; Set output to 32 bit mode
IMO32C==400	; Clear output in 32 bit mode
IMPODS==1000	; Set Output Done
IMPIR==4000	;* Copied to IMPIC; 1= Enable int on imp ready
IMPHEC==10000	; Clear Host Error
;IMIIHE==40000	;* Copied to IMPIHE; 1= Inhibit int on host error
IMPLHW==200000	; Set Last Host Word (do this before last DATAO of msg)

];DMIMP
IFN DMIMP,[	;HARDWARE DESCRIPTION OF DM IMP INTERFACE (PER RMM)

; Note that all PI level 2 interrupts go to normal ITS location
;	and thence vectored to IMPINT.
; However, PI 1 interrupts go to different places:
;	Input Done -> loc 70 (IMPILC)
;	Output Done -> loc 72 (IMPOLC)
;	Control -> Should never get control interrupt at PI 1.
;		Thus for example "Last Imp Word" interrupts go to
;		IMPINT even though input side PIA is 1, because LIW is
;		a control interrupt and control ints are always kept at PI 2.

	;IMP INTERFACE CONO FLAG DESCRIPTION

;COMMON FLAG BITS TO CONTROLLER

		;18-> 0 FOR INPUT SIDE, 1 FOR OUTPUT SIDE
		;19->CLEAR TEST MODE (200000)
		;20->SET TEST MODE (100000)

		;21->CLEAR HOST READY
		;22->SET HOST READY (20000)
		;23->CLEAR IMP-WAS-DOWN (10000)

		;24->FI DEVICE RESET (CLEAR ALL INPUT AND OUTPUT FLAGS) (4000)

;CONO FI (424) TO OUTPUT SIDE
	;BIT	;18->IS '1' INDICATING TO OUTPUT
		;25->CLEAR OUTPUT 32-BIT MODE
		;26->SET OUTPUT 32-BIT MODE

		;27->SET OUTPUT EOT (CLEAR DONE, SET BUSY) (400)
		;28->SET OUTPUT DONE (200)
		;29->RESET OUTPUT (CLEAR ALL OUTPUT FLAGS) (100)

		;30-32->CONTROL PI ASSIGNMENT

		;33-35->OUTPUT DONE PI ASSIGNMENT

;CONO FI (424) TO INPUT SIDE
	;BIT	;18->IS '0' INDICATING TO INPUT
		;25->CLEAR 32-BIT MODE (2000)
		;26->SET 32-BIT MODE (1000)

		;27->SUSPEND INPUT (400) DATAI WONT SET BUSY NOW
		;28->SET INPUT BUSY (LISTENING TO NETWORK) (200)
		;29->RESET INPUT (CLEAR ALL INPUT FLAGS!) (100)

		;30-32->CONTROL PI ASSIGNMENT

		;33-35->INPUT DONE PI ASSIGNMENT

	;FI CONI FLAG DESCRIPTION

	;BIT	;00->TEST MODE IS ENABLED
		;08->OUTPUT IS IN 32-BIT MODE
		;17->INPUT IS IN 32-BIT MODE

		;18->IMP IS DOWN
		;19->IMP WAS DOWN
		;20->HOST READY (?)

		;21->OUTPUT EOT ON
		;22->OUTPUT BUSY
		;23->OUTPUT DONE
		;24-26->OUTPUT-DONE PI ASSIGNMENT

		;27->INPUT EOT ON
		;28->INPUT BUSY
		;29->INPUT DONE

		;30-32->CONTROL INTERRUPT PI ASSIGNMENT

		;33-35->INPUT DONE PI ASSIGNMENT

;	SYMBOL ASSIGNMENTS FOR DM HARDWARE

;	CONO BITS

FIIN==000000	;(SIC) SPECIFY CONO FOR INPUT
FIOUT==400000	;SPECIFY CONO FOR OUTPUT SIDE
;FITSTC==200000	;CLEAR TEST MODE
;FITSTS==100000	;SET TEST MODE

;FIHSTC==040000	;CLEAR HOST READY
FIHSTS==020000	;SET HOST READY
FIIWDC==010000	;CLEAR "IMP WAS DOWN"

FIRSET==004000	;DO LOCAL IOB RESET FOR FI DEVICE

;INPUT SIDE ONLY

FII32C==002000	;CLEAR 32 BIT MODE, INPUT
FII32S==001000	;SET 32 BIT MODE, INPUT

FISUSP==000400	;"SUSPEND INPUT" CLEAR FLAG, NOT SET BUSY
FIIBSY==000200	;SET INPUT BUSY, ALLOWS BITS IN FROM IMP
FIIDC==000100	;CLEAR INPUT DONE

;	0000X0	;CONTROL PIA

;	00000X	;INPUT DONE PIA

;OUTPUT SIDE ONLY

FIO32C==402000	;CLEAR 32 BIT MODE, OUTPUT
FIO32S==401000	;SET 32 BIT MODE, OUTPUT

FILHW==400400	;SET "LAST HOST BIT TO IMP"
FIODS==400200	;SET OUTPUT DONE
FIODC==400100	;CLR OUTPUT DONE

;	0000X0	;CONTROL PIA

;	40000X	;OUTPUT DONE PIA

;	CONI BITS

;	LEFT HALF OF CONI WORD FOR FOLLOWING 3 BITS

;FITSTM==400000	;TEST MODE IS ON
;FIO32==001000	;OUTPUT IS IN 32 BIT MODE
FII32==000001	;INPUT IS IN 32 BIT MODE

;	RIGHT HALF OF CONI

FIDOWN==400000	;IMP IS DOWN
FIWASD==200000	;IMP WAS DOWN (OR IS) SINCE LAST RESET
;FIHSTR==100000	;HOST READY IS SET ON

;FIOEOT==040000	;OUTPUT LAST IMP BIT IS ON
;FIOBSY==020000	;OUTPUT IS BUSY AFTER DATAO
FIOD==010000	;OUTPUT IS DONE, (INTERRUPTING)

;	00X000	;OUTPUT DONE PIA

FILW==000400	;LAST BIT SET FROM IMP
FIIBSY==000200	;INPUT IS BUSY, WORD BEING ASSEMBLED FROM IMP
FIID==000100	;INPUT IS DONE (INTERRUPTING) TO DO DATAI

;	0000X0	;CONTROL PIA

;	00000X	;INPUT PIA

IMPLW==FILW	;USEFUL TO TEST IN AC
IMP==FI		;USEFUL FOR BLKO, DATAO INSTR
]

; IMP 1822 PROTOCOL INFORMATION (EXTENDED-LEADER VERSION)

; The IMP leader is 96 bits long, usually organized as 3 words of 32 bits.
; For further details, these documents are available from the Network
; Information Center:
;	IMP-HOST protocol: BBN Report No. 1822
;	NCP protocol: NIC 8246, Host-to-Host Protocol for the ARPANET
;	IP, TCP: Internet Protocol Transition Workbook, and
;		 Internet Protocol Implementor's Guide
;
; For the benefit of the NCP code, ITS reads in the leader as 36-bit words
; with sufficient IMP padding (5 16-bit wds) to cause NCP data to be aligned
; on a word boundary. The first 4 words of the leader are read
; in 36-bit mode:
;------------------------------------------------------------------------
;1:  4.9-4.6 not used (0)
;    4.5-4.2 all 1's for new format, else old msg type (4=old nop)
;    4.1-3.3 network number (0)
;    3.2-2.8 not used (0)
;        2.7 trace (ignored)
;    2.6-2.4 leader flags (2.6 is to be ignored, 2.5-2.4 are not used!)
;    2.3-1.5 message type (as of yore, but more bits) (see IMTDT)
;    1.4-1.1 high 4 bits of handling type (0)
;
;2:  4.9-4.6 Low bits of handling type (7 for big buffers, 4 for small buffers,
;    4.5-3.7 host number			and 0 for the control link)
;    3.6-1.9 Imp number
;    1.8-1.1 Link number (high 8 bits of message-id)
;
;3:  4.9-4.6 Low 4 bits of message-id (0)
;    4.5-4.2 Sub-type
;    4.1-2.4 Message length (ignored)
;    2.3-1.1 Padding
;------------------------------------------------------------------------
;		All non-regular messages (ie Host-Imp, not Host-Host)
;		stop here, since padding and data only exist for regular
;		messages (Type 0).
;------------------------------------------------------------------------
;4:  4.9-1.1 Padding
;------------------------------------------------------------------------
;		At this point there are still 32 bits of padding left.  The
;		Internet Protocol messages are vectored off here (they are
;		identified by a message-type of 0 and a link-number of 233).
;------------------------------------------------------------------------
; HOST-HOST REGULAR MESSAGES
;	NETWORK CONTROL PROTOCOL (NCP) - read in 36-bit mode
;5:  4.9-1.5 Padding
;    1.4-1.1 M1 Host-host padding
;
;6:  4.9-4.6 M1 Host-host padding	; NCP leader contained in this word.
;    4.5-3.7 S  Byte size
;    3.6-1.9 C  Byte count
;    1.8-1.1 M2 Host-host padding
;------------------------------------------------------------------------
; HOST-HOST REGULAR MESSAGES
;	INTERNET PROTOCOL (IP) - read in 32-bit mode
;5:  4.9-1.5 Padding
;6:  4.9-1.5 First word of IP datagram
;------------------------------------------------------------------------

;In message types 2 and 6, the going-down status 16-bit word is
;in word 2 1.8-1.1 and word 3 4.9-4.2.

;4.5-4.2 of word 3 are the padding count for type 4 (nop) from host.
;This is 5.  Padding is only put on type-0 messages.

IMTBP:	041000,,IMPILB+0	;BYTE POINTER FOR MESSAGE TYPE FIELD
IMOTBP:	340400,,IMPILB+0	; Byte ptr for message format type
IMLNBP:	001000,,IMPILB+1	;BYTE POINTER FOR LINK NUMBER FIELD
IMSABP:	103000,,IMPILB+1	; Byte ptr for source address field (host+imp)
IMSHBP:	301000,,IMPILB+1	;BYTE POINTER FOR SOURCE HOST FIELD
IMSIBP:	102000,,IMPILB+1	;BYTE POINTER FOR SOURCE IMP FIELD
IMSTBP:	340400,,IMPILB+2	; Byte ptr for subtype field
IMCBBP:	301000,,IMPILB+5	;BYTE POINTER FOR CONNECTION BYTE SIZE FIELD
IMBCBP:	102000,,IMPILB+5	;BYTE POINTER FOR BYTE COUNT FIELD


SUBTTL	ARPANET VARIABLES AND TABLES

IFN NCPP,[
IMPSTL==NNETCH	;SOCKET TABLE LENGTH (MUST BE .LE. 70)
IFG NNETCH-70,.ERR NNETCH SHOULD BE LESS THAN 70 OCTAL, PER BBN SPECS
];NCPP

IFN INETP,[
IMPCLP:	0	; HACK!! # to use for control-link link field.
]
EBLK

IMPN::		;IMP DATA AREA CLEARED WHEN IMPUP
IFN INETP,[
%IMXLN==:<<8159.-96.>+31.>/32.	; Max # of 32-bit words in IMP regular msg,
		; exclusive of leader and leader padding.  = 252.
IMPIBS:	0	; Saved initial BLKI pointer for IP datagram read
IMPIDP:	0	; Pointer to IP datagram being input at PI level
IMPODP:	0	; Pointer to IP datagram being output at PI level
IMPPSW:	0	; Flip-flop to alternate output of IP and NCP msgs
]
IFN KAIMP,[
IMPI:	0	;-1 => IMPCHN INPUT INTERRUPT OCCURRED
IMPO:	0	;-1 => IMPCHN OUTPUT INTERRUPT OCCURRED
IMPB:	0	;-1 => IMPCHN FLAG INTERRUPT OCCURRED
IMPIH:	0	;-1 => INPUT WANTS PIA = IMPCHN
IMPOH:	0	;-1 => OUTPUT WANTS PIA = IMPCHN
]
IMPIS:	0	;INPUT STATE
 %ISIDN==:-1	; Network shut off
 %ISIDL==:0	; Normal - idle, not expecting input (i.e. between msgs)
 %ISIGN==:1	; Ignore input until end of current message (36 bit mode)
 %ISIML==:2	; Reading IMP initial leader	(36 bit mode)
 %ISINC==:3	; Reading NCP control message	(32 bit mode)
 %ISIND==:4	; Reading NCP data message	(32 or 36 bit mode)
 %ISINL==:5	; Reading NCP-type IMP leader	(36 bit mode)
 %ISIIL==:6	; Reading IP-type IMP leader	(32 bit mode)
 %ISIID==:7	; Reading IP datagram		(32 bit mode)

IMPOS:	0	;OUTPUT STATE
 %ISODL==:0	; Not expecting output done (i.e. between messages)
 %ISONC==:1	; Sending NCP control message
 %ISOND==:2	; Sending NCP data message
 %ISOID==:3	; Sending IP Datagram

IMPHI:	0	;-1 TO HOLD UP INPUT
		;-2 INPUT IS SUCCESSFULLY HELD UP
IMRFCT:	0	;NUMBER OF HOST TABLE ENTRIES WITH PENDING
		;TIMEOUTS FOR CONTROL-LINK RFNM OR RST-RRP.

; ACTIVE HOST TABLE.  Entries herein are allocated as needed, using garbage
; collection.  Most "host number" fields are really indices into
; this table.
LIMPHT==<NNETCH/2+3>+<XBL+5>	; NCP conns plus TCP conns plus a few extra
IMPHTN:	BLOCK LIMPHT	; Host number.  1.1-1.8 HOST, 2.1-3.7 IMP
IMPHTB:	BLOCK LIMPHT	;BITS:
		;4.9 1=RFNM WAIT ON LINK 0 (NCP)
		;4.8 GC MARK BIT
		;4.7-4.3 UNUSED
		;4.2-4.1 STATUS OF HOST 0 DOWN, 1 RST SENT, 2 UP
		;3.9-3.1 TIME (MOD 2**9) LAST RFNM SENT ON LINK 0 (NCP)
	.SEE IMPHDS	;RH   LAST MESSAGE FROM IMP ABOUT "HOST DEAD STATUS"
IMPHTC:	BLOCK LIMPHT	; # active messages outstanding for host (8 max)
IMPHTT:	BLOCK LIMPHT	; Time of last RFNM received

IMNCS:	0	;NUMBER OF CHANNELS BEING CLOSED
IMNAS:	0	;NUMBER OF CHANNELS WITH 4.8 IN IMSOC5 SET
LIMPN==.-1 ;LAST LOCATION BLT'ED TO ZERO WHEN INITIALIZED
IMNBLK:	0	; Number of times blockage avoided (output held up by ITS)
IMPHTF:	-1	;HOST TABLE FREE LIST, THREADED THROUGH IMPHTB, END WITH -1
IMPUP:	-1	;0 => IMP UP  ;-1 => DOWN  ;-2 => COMING UP, PI LVL STILL OFF
		;1 => DOWN FOR GOOD, UNTIL NEXT TIME IMP READY LINE CHANGES
IMPTCU:	0	;0 IMP UP/DOWN STATUS NOT CHANGING
		;>0 TRYING TO REINITIALIZE, SYS JOB HASN'T DONE SO YET
		;-1 HAS BEEN REINITIALIZED, HAVEN'T EXCHANGED NOPS YET
IMPUCT:	0	;IMP COMING UP TIMEOUT, IF 4 NOOPS DON'T GO THROUGH PROMPTLY.
IMPDWN:	BLOCK 3	;LAST MESSAGE FROM IMP THAT IT IS GOING DOWN
		;WD0 "REASON" CLAIMED BY IMP (SEE CH 3 OF BBN REPORT 1822)
		;WD1 TIME WHEN EXPECTED DOWN
		;WD2 TIME WHEN EXPECTED UP (SYS TIME=1/30 SEC SINCE UP)
IFN KAIMP,IMPPIA: 0	;CURRENT IMP PIA
IMPCNI:	0	;CONI INTO HERE AT SLOW CLOCK LEVEL
IMERCN:	-1	;CONI INTO HERE WHEN NET GOES DOWN
IMNOPC:	0	;< 0 => SEND NOPS
IMPA:	0	;SAVE A AT IMPCHN PI LEVEL
IMPOAC:	-1	;-1 => OUTPUT INACTIVE
IMPERB:	BLOCK 5	;LAST "ERR" MESSAGE FROM A HOST
		;WD 0 TIME WHEN RCVD, WD 1 HOST, WD2-4 11. 9-BIT BYTES OF DATA
IFN DMIMP,IMPSUS: 0	;HOLDS INPUT WORD WHILE INPUT IS HELD UP
IMPILB:	BLOCK 6		;INPUT LEADER BUFFER
IMPINB:	BLOCK 30.+5	;30. WORDS @ 32 BITS/WD = 120. 8 BIT BYTES
			;+5 WORDS FOR GOOD MEASURE
			;THIS BUFFER IS FOR CONTROL-LINK MESSAGES
BBLK

IMHSBT:	330200,,IMPHTB(H)	;RST/RRP STATUS

EBLK

IMPCSH:	-1	;CURRENT SOURCE HOST (IMPHTB INDEX).  -1 WHEN IDLE.
IMPCLN:	0	;CURRENT LINK NUMBER
IMPCBS:	0	;CURRENT BYTE SIZE
IMPCBC:	0	;CURRENT BYTE COUNT
IMPNIW:	0	;EXPECTED LAST BLKI ADDRESS
IMNWSI:	0	;SECOND BLKI POINTER, ZERO IF NONE
IMPSVP:	0	;SAVE PIA AT IMPRMP
IMPSVQ:	0	;SAVE CONTROL MESSAGE QUEUE POINTER AT IMPOB2
IMBLKI:	0	;PLACE TO STORE BLKI POINTER
IMBLKO:	0	;PLACE TO STORE BLKO POINTER
IMPNBI:	0	;AMOUNT TO INCREMENT IMSMPC(I) BY, I.E. # OF DATA BYTES
		; IN MESSAGE CURRENTLY COMING IN AT P.I. LEVEL
IMPNBO:	0	;AMOUNT TO INCREMENT IMSMPC(I) BY, I.E. # OF DATA BYTES THAT WILL BE
		; MADE FREE IN BUFFER BY MESSAGE CURRENTLY GOING OUT AT P.I. LEVEL
IMPNBT:	0	;# BITS ACTUALLY BEING SENT, USED TO ADJUST ALLOCATION
IMPNPT:	0	;NEW VALUE FOR IMSPIP(I) AFTER MSG IS SENT
IMPIPI:	-1	;IMSOC INDEX ACTIVE FOR INPUT AT P.I. LEVEL, OR -1 IF NONE
IMPOPI:	-1	;IMSOC INDEX ACTIVE FOR OUTPUT AT P.I. LEVEL, OR -1 IF NONE
IMOB0Z:	0	;IMSMPP AT IMOBD1, FOR DEBUGGING

;IMP OUTPUT LIST.  EXECUTED AT PI LEVEL 1.
;NEGATIVE = BLKO POINTER, 0=STOP, 1=SET LAST WORD, 2=32-BIT MODE, 3=NOP
IMOPNT:	0	;INDEX OF NEXT "INSTRUCTION" IN IMP OUTPUT LIST:
IMOLST:	0	;BLKO FOR SECOND THROUGH SIXTH LEADER WORDS (FIRST IS DATAO'ED)
IMOMOD:	2	;SWITCH TO 32-BIT MODE IF NECESSARY
IMOBK1:	0	;FIRST BLKO POINTER
IMOBK2:	0	;SECOND BLKO POINTER
	1	;SET LAST WORD
IMOBK3:	0	;THIRD BLKO POINTER (SEND LAST WORD, NOT USED WITH DM INTERFACE)
	0	;STOP
IMOLDR:	BLOCK 6	;BUILD PREAMBLE HERE FOR DATA MESSAGES

IMPNEA:	0	;NUMBER OF ECOS IN COMMAND MESSAGE THAT HAVE BEEN ANSWERED
IMPNRA:	0	;NUMBER OF RSTS ANSWERED

;METERS
IFN INETP,[
IMNIPI:	0	; # of IP datagrams input (rcvd)
IMNIPF:	0	; # of IP datagrams flushed (input threw away)
IMNIPO:	0	; # of IP datagrams output (sent)
IMNIPR:	0	; # of IP RFNMs received
IMNIP7:	0	; # of IP Type 7 (Dest Host Dead) messages received
IMNIP8:	0	; # of IP Type 8 (Error) msgs rcvd
IMNIP9:	0	; # of IP Type 9 (Incomplete Transmission) msgs rcvd
IMNWIG:	0	; # words ignored by "Ignore" state (%ISIGN)
IMNWIF:	0	; # words flushed by IMPRM5
] ;INETP
IFN NCPP,[
IMNOSH:	0	;# OF SHUFFLES OF NET OUTPUT BUFFERS
IMNISH:	0	;# OF SHUFFLES OF NET INPUT BUFFERS
IMNSCM:	0	;NUMBER OF SHORT CONTROL LINK MESSAGES
IMPNEI:	0	;NUMBER OF ERPS NOT SENT
IMPNRI:	0	;NUMBER OF RRPS NOT SENT
IMNRFC:	0	;NUMBER OF RFCS CLSED
IMNRFI:	0	;NUMBER OF RFCS IGNORED
IMNCLI:	0	;NUMBER OF CLS IGNORED
IMNALI:	0	;NUMBER OF ALLS IGNORED
IMNPIL:	0	;NUMBER OF TIMES PI CONTROL QUEUE EXCEEDED
IMNCNS:	0	;NUMBER OF CLS NOT SENT
IMNANS:	0	;NUMBER OF ALLS NOT SENT
IMNMNC:	0	;NUMBER OF REGULAR MESSAGES FOR NON-EXISTANT CONNECTIONS
IMNMAE:	0	;NUMBER OF TIMES MSG ALL EXCEEDED
IMNMSS:	0	;NUMBER OF TIMES MSG SHORT
IMNBAE:	0	;NUMBER OF TIMES BIT ALL EXCEEDED
] ;IFN NCPP
IMPNPE:	0	;NUMBER OF PROTOCOL ERRORS
IMNSRC:	0	;NUMBER OF SPURIOUS RFNMS ON CONTROL LINK
IMNSRF:	0	;NUMBER OF SPURIOUS RFNMS ON REG CONNECTIONS
IMNRFN:	0	;NUMBER OF RFNMS NOT SENT
IMSTAS:	0	;STATUS OF INPUT AT TIME HELD UP
IMPNIH:	0	;NUMBER OF TIMES INPUT SUCCESSFULLY HELD UP
IMPNUH:	0	;NUMBER OF TIMES INPUT HOLDUP UNDONE
IMRFTO==60.*30.	;RFNM WAIT TIME OUT
IFN NCPP,[
IMNORH:	0	;NUMBER OF STYNET OUTPUT RESETS DELAYED
;IMPRTO==30.*60.	;RESET TIME OUT (IDENTICALLY = IMRFTO)
IMPCTO==30.*30.	;CLS TIME OUT
IMFCTO==55.*30.	;RFC QUEUE TIME OUT - SHOULD BE LESS THAN 2*IMPCTO
IMPCMR:	BLOCK 20	;COUNT OF CONTROL MESSAGES RCD
IMPCMS:	BLOCK 20	;COUNT OF CTL MSG SENT
] ;IFN NCPP
IMPMSR:	BLOCK 20	;COUNT OF IMP MESSAGES RCD
IMPM1S:	BLOCK 4		; # Type 1 (Error in Leader) subtype msgs
IMPM9S:	BLOCK 20	; # Type 9 (Incomplete Transmission) subtype msgs
IMPMSS:	BLOCK 1		;COUNT OF IMP MSG SENT (WE ONLY SEND REGULAR MSGS)
IMCT1:	0	;# TIMES AT IMPBKZ
IMCT2:	0	;# TIMES AT IMPIBZ
IMCT3:	0	;# TIMES AT IMPOBZ
BBLK

SUBTTL	ARPANET MAIN-PROGRAM LEVEL

IMPINI:
IFN KAIMP,[
	CONO IMP,IMI32C
	DATAI IMP,A
	CONO IMP,IMPODC		;CLEAR OUTPUT DONE AND PIA
	CONSZ IMP,IMPOD+7	;CHECK OUTPUT DONE, PIA, CAUSE HOST READY
	 JRST 4,.		;CONO DIDN'T CLEAR SOME BITS?
	CONO IMP,IMPIR+IMPHEC	;CLEAR HOST ERR, ENABLE INT ON IMP READY
]
IFN DMIMP,[
	CONO FI,FIRSET	;RESET IMP INTERFACE, SET HOST READY
	CONO FI,FIHSTS
]
	SETOM IMPIPI
	SETOM IMPOPI
	MOVE T,TIME
	ADDI T,15.
	CAMLE T,TIME
	 PUSHJ P,UFLS	;WAIT FOR HALF SECOND
IFN KAIMP,[
	CONO IMP,0	;CLEAR "ENABLE IMP READY" INT (TURNS OFF IMP ERROR)
	MOVEI A,NETCHN	;IDLE PIA
	MOVEM A,IMPPIA
	MOVE A,[JSR IMPIBK]
	MOVEM A,IMPILC
	MOVE A,[JSR IMPOBK]
	MOVEM A,IMPOLC
]
IFN DMIMP,CONO FI,FIIWDC	;CLEAR "IMP WAS DOWN"
IFN NCPP,[
	MOVSI I,-IMPSTL
IMPINA:	SKIPE IMSOC6(I)
	 JRST 4,.
	SETZM IMSOC1(I)
	AOBJN I,IMPINA
] ;IFN NCPP
	SETZM IMPILC+1
	SETZM IMPOLC+1
	SETOM IMPOAC
	SETOM IMPUP	;NOT UP YET
	MOVNI A,20.	;ALLOW 10 SECONDS TO COME UP
	MOVEM A,IMPUCT
	SETOM IMPTCU	;TRYING TO COME UP
	SETOM IMPHTF	;WILL GC IMPHTB ON FIRST REFERENCE
IFN NCPP,[
	SETOM IMPMPU
	SETOM IMPMPL
	SETOM IMPNCQ
	SETOM IMPLCQ
	MOVEI I,IMNPIC
	MOVEM I,IMFCQL
	MOVEI A,IMPCQ
	MOVEM A,IMFFCQ
	JRST IMPIN1

IMPIN2:	ADDI A,IMPMQS+1
	MOVEM A,-IMPMQS-1(A)
IMPIN1:	SOJG I,IMPIN2
	SETOM (A)
	SETOM IMPBPQ
	SETOM IMPEPQ
	MOVEI A,IMPPQ
	MOVEM A,IMFFPQ
	MOVEI I,IMNPQ
	JRST IMPIN4

IMPIN3:	ADDI A,4
	MOVEM A,-4(A)
IMPIN4:	SOJG I,IMPIN3
	SETOM (A)
	MOVEI A,NETSRS
	MOVEM A,NRSOC
];NCPP
	MOVE A,[IMPN,,IMPN+1]
	SETZM IMPN
	BLT A,LIMPN
	SETOM IMPIS		; Say IMP shut off
	MOVE T,TIME
	MOVEM T,LNETIM
IFN KAIMP,CONO IMP,NETCHN
IFN DMIMP,[
	CONSZ FI,FIDOWN+FIWASD	;SKIP IF STILL UP
	 POPJ P,	;LOSE IF NOT IMP UP
	CONO FI,FIIN\FIIBSY+NETCHN*11
	CONO FI,FIOUT+NETCHN*11
]
	SETOM IMPDWN+1	;TIME FOR IMP TO GO DOWN, NOT KNOWN
	;MOVE T,TIME
	ADDI T,15.
	CAMLE T,TIME
	 PUSHJ P,UFLS
	SETZM IMPIS	; Say up but idle
	MOVNI A,4
	MOVEM A,IMNOPC	;SEND 4 NOPS
IMPOST:	CONO PI,NETOFF
IFN DMIMP,[
	CONSO FI,70	;SKIP IF PIA NON-ZERO
	 JRST NETONJ	;IF NO PIA, THEN DONT SET INT
]
IFN KAIMP,MOVE TT,IMPPIA	;MAIN PROGRAM OUTPUT START
	AOSN IMPOAC	;SKIP IF OUTPUT ALREADY ACTIVE
IFN KAIMP, CONO IMP,IMPODS(TT)	;GENERATE OUTPUT INTERRUPT
IFN DMIMP, CONO FI,FIODS+NETCHN*11
	JRST NETONJ

IMPIOS:
IFN KAIMP,[
	AOSE IMPOAC	;PI LEVEL OUTPUT START
	 POPJ P,
	PUSH P,TT
	CONO PI,400	;TURN PI OFF, IMP MAY HAVE PIA = 1
	MOVE TT,IMPPIA
	CONO IMP,IMPODS(TT)
	CONO PI,200
	POP P,TT
]IFN DMIMP,[
	AOSN IMPOAC
	 CONO FI,FIODS+NETCHN*11
]
	POPJ P,



;Check if IMP ready line is set
; Called from SYSJOB.
; Return +1 if IMP not ready, +2 if so
;
IMPCKR:
IFN DMIMP,[
	.ERR IMPCKR Missing for DMIMP!
]
IFN KAIMP,[
	CONSZ IMP,IMPR		;Skip if IMP not ready
	 AOS (P)		;Return +2 if ready
	POPJ P,
]


SUBTTL	HOST-TABLE MANAGEMENT

; FNDHST - Look up host-table index for a given IMP host address.
;	Call with NETOFF or NETCHN PI in progress.
;	T/ IMP host address (maybe someday other nets?)
; Returns .+1 if failed (no room in table)
; Returns .+2
;	H/ host-table index
; Smashes W.

FNDHST:	MOVEI H,LIMPHT-1	;SEARCH FOR AN ENTRY FOR THIS HOST
	CAME T,IMPHTN(H)
	 SOJGE H,.-1
	JUMPGE H,POPJ1		;FOUND
	SKIPGE H,IMPHTF		;NOT FOUND, CONS ONE OFF FREE LIST
	 JRST FNDHS1		;OOPS, MUST GARBAGE COLLECT
	MOVE W,IMPHTB(H)
IFN INETP,[		; Later make this check standard!
	CAIGE H,LIMPHT		; Make sure H is valid idx
	 CAIL W,LIMPHT		; ditto W
	  BUG HALT,[NET: FNDHST idx clobbered!!!]
]
	MOVEM W,IMPHTF
	MOVEM T,IMPHTN(H)
	SETZM IMPHTB(H)		;NOTHING IS KNOWN ABOUT THIS HOST
	SETZM IMPHTC(H)		; Assume no RFNMs outstanding
	SETZM IMPHTT(H)		; Clear out time of last RFNM.
	JRST POPJ1

; Host-Table full, attempt to GC it and flush unused entries, by
; scanning all possible pointers into table.
;	IMP pointers are IMPCSH and IMPHTC(H)
;	NCP pointers are IMSOC4<3.9-4.7>, RFC queue, PI ctl msg queue,
;		and the RFNM-wait and RST-sent bits in table.
;	TCP pointers are XBNADR(I)

	; GC mark phase - mark entries in use
FNDHS1:	PUSH P,I
	MOVSI W,200000		;MARK BIT
	MOVEI H,LIMPHT-1	;CLEAR ALL MARK BITS
	ANDCAM W,IMPHTB(H)
	SOJGE H,.-1
	SKIPL H,IMPCSH		;MARK FROM IMPCSH
	 IORM W,IMPHTB(H)

IFN TCPP,[
	MOVEI I,XBL-1
	SKIPL H,XBNADR(I)	; See if TCP conn has a net addr specified
	 IORM W,IMPHTB(H)	; Yes, set the mark bit.
	SOJGE I,.-2
] ;IFN TCPP
IFN NCPP,[
	MOVEI I,IMPSTL-1	;MARK FROM IMSOC4
FNDHS2:	SKIPN IMSOC1(I)		;SKIP IF IMSOC4 IS BEING USED BY ANYONE
	 SOJGE I,FNDHS2
	JUMPL I,FNDHS3
	LDB H,IMSCFH
	CAIE H,377
	 IORM W,IMPHTB(H)
	SOJGE I,FNDHS2
FNDHS3:	MOVE I,IMPBPQ		;MARK RFC PENDING QUEUE
	JUMPGE I,[ LDB H,[101000,,3(I)]
		   IORM W,IMPHTB(H)
		   MOVE I,(I)
		   JRST . ]
	MOVE I,IMPNCQ		;MARK CONTROL QUEUE
	JUMPGE I,[ HLRZ H,1(I)
		   IORM W,IMPHTB(H)
		   MOVE I,(I)
		   JRST . ]
] ;NCPP

	; GC sweep phase - free all unmarked entries
	SETO I,			;FREE POINTER
	MOVEI H,LIMPHT-1
	MOVSI W,601000		;PROTECT IF RFNM-WAIT, RST-WAIT, OR MARKED
FNDHS4:
	SKIPG IMPHTC(H)		; Also protect if any outstanding RFNMs
	 TDNE W,IMPHTB(H)
	  SOJGE H,FNDHS4
	JUMPL H,FNDHS5
	SETZM IMPHTN(H)		;DON'T BELONG TO ANY HOST
	MOVEM I,IMPHTB(H)	;CONS ONTO FREE LIST
	MOVE I,H
	SOJGE H,FNDHS4
FNDHS5:	MOVEM I,IMPHTF		;FREE LIST
	POP P,I
	SKIPGE IMPHTF
	 POPJ P,		;GC-OVERFLOW
	JRST FNDHST		;TRY AGAIN, SHOULD WIN

SUBTTL	ARPANET INPUT INTERRUPT LEVEL

COMMENT |
	The IMP interrupt level structure is fairly complicated and
deserves some explanation.  Because the IMP interface is not a DMA
device, all I/O is done "by hand", a word at a time; for this reason
all I/O is done at PI level IMPCHN=1 (the highest) whenever possible.
However, to prevent general IMP processing from taking complete
precedence over everything else, all non-I/O handling is done at
PI level NETCHN=2, which is the same level as disk devices.
	The MIT-DMS interface (DMIMP) is much more complicated than the
AI-KA/ML/MC interface and was designed to facilitate this dual-level
interrupt processing by providing different PI channel assignments
for each of 3 possible conditions:
	Input Done  (must usually read next word)
	Output Done (must usually output next word)
	Control Int (some unusual condition, including Last-IMP-Word)

Because the non-DM interface only has one PI assignment available,
the software to switch levels is much more complicated.  For either
case, the code will not make sense unless you understand the channel 1
multiplexing feature (see interface CONI bit descriptions).
|

; Here when IMP interface is interrupting at PI level 2 (NETCHN)
; TT has CONI bits.  Can clobber most ACs

IMPINT:
IFN KAIMP,[
	AOSN IMPB	; PI 1 control interrupt?
	 JRST IMPBKZ	;   Yes
	AOSN IMPI	; PI 1 Input Done interrupt?
	 JRST IMPIBZ	;   Yes
	AOSN IMPO	; PI 1 Output Done interrupt?
	 JRST IMPOBZ	;   Yes already
	TRNE TT,IMPLW+IMPHER+IMPERR	; No PI 1 ints, check status bits
	 JRST IMPBKZ	; PI 2 Control interrupt (error or Last Imp Word)
	TRNE TT,IMPID
	 JRST IMPIBZ	; PI 2 Input Done
	TRNE TT,IMPOD
	 JRST IMPOBZ	; PI 2 Output Done
]IFN DMIMP,[
	TRNE TT,FILW+FIWASD+FIDOWN
	 JRST IMPBKZ	; PI 2 Control interrupt (error or Last Imp Word)
	TRNE TT,FIID
	 JRST IMPIBZ	; PI 2 Input Done
	TRNE TT,FIOD
	 JRST IMPOBZ	; PI 2 Output Done
]
	JRST 4,.	; Must be one of above!!

IFN KAIMP,[
; IMPIBK - Default PI 1 Input Done routine, called from IMPILC.
;	We're idling, switch to PI 2 to handle the input
;	(normally 1st word of new IMP message)
EBLK
IMPIBK:	0
BBLK
	SETOM IMPI		; Set flag saying PI 1 Input Int seen
	CONO IMP,NETCHN		; Switch PIA to 2
	JRST 12,@IMPIBK		; Go re-interrupt, will get to IMPINT->IMPIBK
]

IFN KAIMP,[

; IMPBRK - PI 1 Control interrupt, called from PI0LOC+2 (= 42 on KA's)
;	which is the standard PI 1 vector location.
;	Again, switch to PI 2 to handle the condition
;	(typically Last Imp Word seen on input)
EBLK
IMPBRK:	0		; This interrupt is to 42, may not be the IMP
BBLK
	CONSO IMP,IMPLW+IMPHER+IMPERR	; This really from the IMP?
IFE NEWDTP,JRST RC1INT
IFN NEWDTP,JRST IMPBR1
	SETOM IMPB		; Yes, re-interrupt and handle at NETCHN level
	CONO IMP,NETCHN		; Switch PIA to 2 (NETCHN)
	JRST 12,@IMPBRK		; Go re-interrupt, will get to IMPINT->IMPBKZ

IFN NEWDTP,[
IMPBR1:	CONSZ DTC,70		; Allow for non-IMP interrupt on PI chan 1
	 JRST 12,@IMPBRK
]

RC1INT:	MOVEM 17,R1NTAC+17
	MOVEI 17,R1NTAC
	BLT 17,R1NTAC+16
	MOVEI J,1
	JSP E,SPUR
	MOVSI 17,R1NTAC
	BLT 17,17
	JRST 12,@IMPBRK
];IFN KAIMP

; IMPRM4 - PI 1 Input-Done handler during readin of IMP data (not leader)
;	BLKI has run out but haven't yet gotten Last Imp Word!
;	Either read more (if 2nd ptr specifed) or ignore following data.
EBLK
IMPRM4:	0
BBLK
	MOVEM A,IMPA	; Save A
	SKIPL A,IMNWSI	; Second BLKI pointer exists?
	 JRST IMPRM6	; Nope, none now
	MOVEM A,IMBLKI	; Yes, store it!
	SETZM IMNWSI	; Clear this flag so don't do it again
	MOVE A,IMPA	; Restore A
	JRST 12,@IMPRM4	; Return, continuing BLKI.

IMPRM6:	MOVE A,[JSR IMPRM5]	; Ugh!  Ignore additional input
	MOVEM A,IMPILC		; Set up new vector to "ignore" routine
	MOVE A,IMPA
	JRST 12,@IMPRM4

; IMPRM5 - PI 1 Input-Done handler while ignoring IMP data, only
;	set up by IMPRM6 above.
;	Just reads a word and ignores it.  This loop is broken
;	by a control interrupt when Last-Imp-Word is seen.
EBLK
IMPRM5:	0		; Hmm? Flush input at PI 1
BBLK
	DATAI IMP,IMPA
IFN INETP,AOS IMNWIF	; See how often we come here.
	JRST 12,@IMPRM5

; IMPIBZ - PI 2 (NETCHN) "Input Done" interrupt, via IMPINT.
;	Note there is one input word waiting in the IMP interface,
;	but it is NOT the last IMP word (if it was, we would get a
;	control interrupt and go to IMPBKZ instead).  This situation
;	should only happen while reading the IMP leader and there is
;	more input than just the leader, i.e. it is a NCP or IP message.
;	This is also where we come after being in idle state.
;	TT/ IMP CONI word

IMPIBZ:	AOS IMCT2
IFN DMIMP,[
	TRC TT,IMPCHN	;FIND IF INPUT PIA=IMPCHN
	TRNN TT,7
	 JRST IMPRET	;YES, ALREADY HANDLED BY IMPCHN
];DMIMP
IFE INETP,[		; Note IP datagram is read in 32-bit mode!
IFN DMIMP,TLNE TT,FII32
IFN KAIMP,TRNE TT,IMPI32
	 JRST 4,.	; NCP-only, leader should always be read in 36-bit mode
] ;IFE INETP
	MOVE C,IMPHI
	SKIPN B,IMPIS	; Skip hold-up check unless at start of msg (idle)
	 AOJE C,IMPBKW	; Jump if input needs to be held up (can only do at start or end of msg)
IFE INETP,CAILE B,%ISIML
IFN INETP,CAILE B,%ISIID
	 JRST 4,.	; Unknown input state
	JRST @.+2(B)	; Dispatch, note data not read yet

		IMPIGN		;-1 Supposed to be shut off, go ignore message.
	OFFSET -.
 %ISIDL::	IMSTR1		; 0 Was idle, this is start of a message!
 %ISIGN::	IMPIGN		; 1 Ignoring this message.
IFE INETP,%ISIML:: IMPLD2	; 2 Reading IMP leader, see what we got.
IFN INETP,[
 %ISIML::	[JRST 4,.]	; 2 Should only see %ISINL or %ISIIL
 %ISINC::	[JRST 4,.]	; 3 Was reading control msg!  Runout is error.
 %ISIND::	[JRST 4,.]	; 4 Was reading NCP data msg! Runout is error.
 %ISINL::	IMPLD2		; 5 Was reading NCP IMP leader
 %ISIIL::	IMPLD2		; 6 Was reading IP IMP leader.
 %ISIID::	[JRST 4,.]	; 7 Was reading IP datagram!  Runout is error.
] ;INETP
	OFFSET 0

IMPIGN:	DATAI IMP,A	; Ignore input (only come here via table above)
IFN INETP,AOS IMNWIG	; See how often we come here.
	;JRST IMPRET

	; All routines dispatched to from IMPIBZ should return via IMPRET.
IMPRET:
IFN DMIMP,CONI FI,A
	SKIPN IMPIS		; Skip if input not in normal (idle) state
IFN KAIMP, CONSO IMP,IMPI32	; It is, see if input is in 32-bit mode
IFN DMIMP, TLNN A,FII32
	  JRST .+2
	   JRST 4,.		; Shouldn't be in 32 bit mode in normal state
IFN KAIMP,CONO IMP,@IMPPIA	; Switch to desired exit PIA
	JRST IMPEX

; IMPBKZ - PI 2 (NETCHN) Control interrupt, via IMPINT.
;	Error or Last Imp Word on input.
;	TT/ IMP CONI word

IMPBKZ:	AOS IMCT1	; Bump count of control interrupts
IFN KAIMP,TRNE TT,IMPERR+IMPHER	; See if error or last-imp-word.
IFN DMIMP,TRNE TT,FIWASD+FIDOWN
	 JRST IMPBER	; Jump if IMP Error or Host Error

	; Not an error, interface has Last Imp Word ready for DATAI'ing!
	MOVE B,IMPHI	; Check here to see if input should be held up
	AOJN B,IMPBKX	; Jump if not.

	; Input must be held up.  Also enter here from IMPIBZ if
	; at start of message (only other time input can be held up).
IMPBKW:
IFN KAIMP,CONO IMP,IMPIDC	; Clear Input Done so we don't re-interrupt
IFN DMIMP,[
	CONO FI,FISUSP	; Suspend input, no bits accepted after DATAI
	DATAI FI,IMPSUS	; Have to read word now
	CONO FI,FIIDC+NETCHN_3	; Have to do this to clear IMP Last Word
]				; (also to clear Input-Done PIA)
	SOS IMPHI	; Set -2 to indicate successfully held up
	MOVEM TT,IMSTAS	; Save status (CONI bits)
	AOS IMPNIH	; Bump meter - count of times input was held up.
	JRST IMPRET

; IMPBKX - Auxiliary to IMPBKZ, PI 2 Control Interrupt
;	Have got Last Imp Word and not holding up input, so go
;	handle end of IMP message.

IMPBKX:
IFN KAIMP,[
	MOVE A,[JSR IMPIBK]	; Get rid of input BLKI
	MOVEM A,IMPILC		; Replace with default switch-PIA vector
	SETZM IMPIH		; Say don't need PI 1 for input any more.
	MOVEI A,NETCHN		; And change exit PIA to 2
	SKIPL IMPOH		; Unless output side still needs PI 1.
	 MOVEM A,IMPPIA		; Set value of PI level desired on exit.
	CONO IMP,IMI32C		; Put back in 36 bit mode to start next msg
	DATAI IMP,A		; Get the last input word for processing
]IFN DMIMP,[
	CONO FI,FII32C+FISUSP	; Hold up bits for following clear
	DATAI FI,A		; Get last input word
	CONO FI,FIIDC+FIIBSY+NETCHN*11	; Now clear Last-Imp-Word
]
	; Enter here from IMOB6 if input had been held up.
IMPBKV:	SKIPGE B,IMPIS		; Unless network has been shut off
	 JRST IMPRET		; (in which case ignore input)
	JRST @IMSDT2(B)		; then go process end of IMP message.

IMSDT2:	OFFSET -.
 %ISIDL::	IMPBKN	; 0 Was idle - leader only 1 word long??
 %ISIGN::	IMPIRT	; 1 Ignore input
 %ISIML::	IMPLD1	; 2 End of IMP leader - can't be regular msg
 %ISINC::	IMPBK3	; 3 End of NCP control message
 %ISIND::	IMPRMB	; 4 End of NCP data input
IFN INETP,[
 %ISINL::	IMPLD1	; 5 End of NCP IMP leader?? Probably error.
 %ISIIL::	IMPLD1	; 6 End of IP IMP leader?? Probably error.
 %ISIID::	IMPRMI	; 7 End of IP datagram
] ;INETP
	OFFSET 0

; Here from table above for old-type leader (1 word)
; IMPBN1 is used by IMPLD2 if long leader has wrong format.

IMPBKN:	MOVEM A,IMPILB		; Store first (and only) word of leader
IMPBN1:	LDB A,IMOTBP		; Get message format type
	CAIN A,4		; Old-type NOP?
	 JRST IMPIRT		;  Just ignore it.
	CAIN A,16		; Is it 1822L format?
	 BUG INFO,[IMP: 1822L leader],OCT,IMPILB
	CAIE A,17		; Is it not the long-leader format?
	 BUG INFO,[IMP: Old-type leader],OCT,IMPILB
	JRST IMPIRT		; Ignore rest of message, if any



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;		IMP LEADER READING/DISPATCH		;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;	Code on this page handles the initial processing of
;;;	IMP messages and dispatches to the appropriate
;;;	routines for each message type.  Only Type 0 ("Regular")
;;;	messages carry Host-Host traffic.

; Here from IMPIBZ only, to handle first word of an IMP message.
; (It's not the last word or IMPBKZ would complain about it)
; Set up a BLKI to get the rest of the leader.

IMSTR1:	DATAI IMP,A		; Get 1st word from interface
	; Entry point from IMPOB6 only to restart input from "held-up" state
	; First word already in A
IMSTRT:	MOVEM A,IMPILB		; Store first word of leader
	MOVEI C,%ISIML		; Set new state = reading rest of IMP leader
IFE INETP,MOVE B,[-4,,IMPILB]	; If not diverting IP, ask for it all.
IFN INETP,MOVE B,[-2,,IMPILB]	; Must vector IP, ask for max 36-bit wds
	JRST IMPRM9	; Go read the leader.

;	The code at IMPLD5 will switch to 32-bit mode at right place if
; the message turns out to be an IP datagram.  Otherwise the message
; is either a NCP Host-Host message, or an IMP-to-Host note of some kind;
; both stay in 36-bit mode.

; Here from IMPBKX only for a leader not followed by any data.
; Last word in A, IMPLW flag in TT.
IMPLD1:	AOS B,IMBLKI		; Update pointer to buffer
	MOVEM A,(B)		; and store last word in right place.
	; Fall through to handle what should be an IMP-Host note.
	; The IMPLW flag distinguishes this entry point from IMPLD2,
	; so we know there isn't a data word in the interface.

; Here from IMPIBZ only, for an IMP leader with more data following;
; almost certainly a "Regular" host-host message.  The 2 possible
; states are:
;	%ISINL - NCP, in 36-bit mode, have read 5 wds and 6th awaits.
;	%ISIIL - IP, in 32-bit mode, have read 4 wds and 5th awaits.
; We can't DATAI the current word from the interface until we know
; what mode the remaining data should be read in.

IMPLD2:
IFN KAIMP,TRNE TT,IMPI32
IFN DMIMP,TLNE TT,FII32
IFE INETP, JRST 4,.		; Input was in 32 bit mode when shouldn't!
IFN INETP,[JRST [MOVE B,IMPIS	; If reading IP IMP leader then 32 bit OK.
		CAIE B,%ISIIL	; Leader read in 32-bit mode, must be IP.
		 JRST 4,.	; It isn't???
		JRST .+1]
] ;INETP
	LDB T,IMOTBP		; Examine new-format flag bits of leader
	CAIN A,16		; Is it 1822L format?
	 BUG INFO,[IMP: 1822L leader],OCT,IMPILB
	CAIE T,17		; to verify that leader is "new" 96-bit fmt.
	 JRST IMPBN1		;   Something else?? Go discard.
	HRRZ B,IMBLKI		;-> LAST WORD READ
	CAIGE B,IMPILB+2	;MUST BE AT LEAST 3 WORDS TO BE VALID
	 JRST IMPLD3
	LDB T,IMLNBP		; Extract link number (high 8 bits of msg-id)
IFN INETP,[
	CAMN T,IMPCLP		; HACK!  If it matches our specified ctl link
	 SETZ T,		;  number, then make it look like ctl link!
]
	MOVEM T,IMPCLN
	LDB T,IMSABP		; Get arpanet address (source host+imp)
IFN 0,[	LDB T,IMSHBP		;SOURCE HOST
	LDB A,IMSIBP		;SOURCE IMP
	DPB A,[112000,,T]	;FORM HOST ADDRESS
] ;ifn 0
	PUSHJ P,FNDHST		;H GETS HOST TABLE INDEX
	 JRST IMPLD9		;HOST TABLE FULL
	MOVEM H,IMPCSH		;SAVE CURRENT HOST
	LDB A,IMTBP		;GET MESSAGE TYPE IN A
	CAILE A,10.
	 JRST IMPUN		;UNKNOWN TYPE
	AOS IMPMSR(A)		;COUNT IMP MSGS RCD
	JRST @IMTDT(A)		;DISPATCH

IMTDT:	IMPRM	; 0 Regular Message
	IMPBE1	; 1 Error in Leader (no msg-id)
	IMPGD	; 2 IMP Going Down
	IMPUN	; 3  -
	IMPIN	; 4 NOP
	IMPRFN	; 5 RFNM - Ready For Next Message (transmit succeeded)
	IMPHDS	; 6 Host Dead Status (general info)
	IMPDHD	; 7 Destination Host Dead (transmit failed)
	IMPBE8	; 8 Error in Data (has msg-id)
	IMPINC	; 9 Incomplete Transmission (transmit failed temporarily)
	IMPIRS	;10 Interface Reset - IMP dropped its ready line

IMPLD9:	BUG INFO,[IMP: Message discarded due to host table full],OCT,IMPILB,OCT,IMPILB+1,OCT,IMPILB+2
	JRST IMPIRT

; Here from IMPLD2 if leader is too short
IMPLD3:	SUBI B,IMPILB-1		;# WDS READ
	BUG INFO,[IMP: Short leader, ],DEC,B,[wds. WD1=],OCT,IMPILB,[WD2=],OCT,IMPILB+1
	;JRST IMPIRT		;FLUSH REST OF MESSAGE

;;; IMP->Host Type 4 - NOP

IMPIN:	JRST IMPIRT	; One more nop from IMP

;;; IMP->Host Type 10 - Interface Reset

IMPIRS:	BUG INFO,[IMP: Interface-reset msg]
	JRST IMPIRT	; Probably nothing useful to do about it.

;;; IMP->Host Type X (e.g. 3, 11-255) - bad type

IMPUN:	BUG INFO,[IMP: Unknown msg type ],OCT,A,[ leader ],OCT,IMPILB,OCT,IMPILB+1,OCT,IMPILB+2
	;JRST IMPIRT

IFE NCPP,[
IMPBK3::		;Ignore NCP messages
IMPRMB::
];NCPP

; Here from all over, to flush rest of this message.
; All non-regular messages (not type 0) return here, as well as some
; errors with regular msgs.
; TT says whether there is any more data to read from this message.
IMPIRT:	SETZM IMPIS	; Assume end of message, reset to normal state
	TRNN TT,IMPLW	; But if we haven't yet read the last word,
	 AOSA IMPIS	; then change state to "Ignore" and flush input.
			; Note skip over following SETZM.

; Regular messages (type 0) return here, when we already know this message
; was completely read.  TT isn't valid.
IMPIR1:	SETZM IMPIS	; Reset to normal idle state
	SETOM IMPCSH	; Say no current host
IFN KAIMP,CONO IMP,IMI32C	; Put world back in 36 bit input mode
IFN DMIMP,CONO FI,FII32C+NETCHN*11
	JRST IMPRET

;;; IMP->Host Type 0 - Regular Host-Host message
;	Unless the source host screwed up and sent a dataless message,
; there is a word waiting to be read from the interface.
; For IP this is the 5th word and we are in 32-bit mode.
; For NCP it's the 6th (the NCP leader) and we're in 36-bit mode.
;	TT/ IMP CONI bits, 
;	B/ addr of last wd input (counted-out BLKI pointer)

IMPRM:	TRNE TT,IMPLW
	 JRST IMPRM3	; Foo, message shouldn't end so soon.  Go barf.
IFE INETP,[
	CAIE B,IMPILB+4	; Check that host-host leader word is next in
	 JRST IMPLD3	;   Barf
	SKIPE IMPCLN	; Skip if link 0 - NCP control msg
	 JRST IMPRMD	;   Data message, go read into user buffer.
]
IFN INETP,[
	SKIPN A,IMPCLN	; Skip unless NCP control link message
	 JRST IMPRM1	; NCP control message, go handle it.
	CAIE A,233	; Is link number the magic cookie for IP?
IFN NCPP, JRST IMPRMD	; No, go handle as NCP data message.
IFE NCPP, JRST IMPIRT	; No, ignore it if we don't have NCP

	; This is an Internet Protocol datagram.  Make sure we are
	; in right mode for reading.
	AOS IMNIPI	; Bump count of IP datagrams received
IFN KAIMP,TRNN TT,IMPI32	; Should already be in 32-bit mode
IFN DMIMP,TLNN TT,FII32
	 BUG PAUSE,[IMP: Reading IP dgm in 36-bit mode]
	DATAI IMP,IMPILB+4	; Okay, read in the padding and get going.
	MOVEI A,%IMXLN	; Specify max size of IMP message
			; (we can't trust msg-len leader field)
	PUSHJ P,IPGIPT	; Call IP module - get input buffer pointer
	 JRST [	AOS IMNIPF	; Punted, bump cnt of datagrams lost
		JRST IMPIRT]	; Flush this message (err msg already printed)
	MOVEM A,IMPIDP	; Save datagram pointer
	MOVEM B,IMPIBS	; Save input BLKI pointer for later check
	MOVEI C,%ISIID	; Set state = reading IP datagram
	JRST IMPRM9	; Go do it.

IMPRM1:	CAIE B,IMPILB+4	; NCP control message, check that NCP leader is next 
	 JRST IMPLD3	;   Barf, short message??
] ;INETP
IFN KAIMP,CONO IMP,IMI32S	; NCP control message, set 32-bit mode
IFN DMIMP,CONO FI,FII32S+NETCHN*11
	DATAI IMP,IMPILB+5	; Get NCP leader word
	LDB A,IMCBBP
	MOVEM A,IMPCBS	; Byte size
	LDB B,IMBCBP
	MOVEM B,IMPCBC	; Byte count
	CAIN A,8	; Byte size should be 8 for control link
	 CAILE B,120.	; Byte count shouldn't be > 120.
	  JRST IMPBCM
	ADDI B,3
	LSH B,-2	; Number of words necessary
	MOVEM B,IMPNIW	; Number of input words expected
	HRLOI B,-1(B)
	EQVI B,IMPINB-1	; BLKI pointer
	MOVEI C,%ISINC	; New state = reading NCP control message

; Set up BLKI.  Pointer in B, state in C.
; This place is jumped to by several things that initiate IMP input,
; specifically IMSTRT, IMPRMT, and IMPRM.

IMPRM9:	MOVEM C,IMPIS
	MOVEM B,IMBLKI
	MOVE B,[BLKI IMP,IMBLKI]
	MOVEM B,IMPILC
	MOVE B,IMPBRO(C)	; Get BLKI runout instruction and set vector;
	MOVEM B,IMPILC+1	; will execute when ptr counts out.
IFN KAIMP,[
	SETOM IMPIH		; Say that input wants high pri
	MOVEI B,IMPCHN		; And set our exit PIA to it (IMP)
	MOVEM B,IMPPIA
]
IFN DMIMP,CONO FI,NETCHN_3+IMPCHN	; Set control PIA = NET, input done = IMP

	JRST IMPRET

	; This table holds the instruction to execute after the input
	; BLKI has counted out the ptr and stored the current input word.
	; Note that if the IMP message ends during the BLKI, a control
	; interrupt will happen instead and control goes to IMPBKZ->IMPBKX
	; where there is another state dispatch table.
	; Normally only %ISIML and %ISINL actually use these instructions;
	; the other states are impossible or expect to read the entire
	; remaining message.
IMPBRO:	OFFSET -.
 %ISIDL::	JRST 4,IMPBRO	; 0 Idle   - shouldn't be BLKI'ing.
 %ISIGN::	JRST 4,IMPBRO+1	; 1 Ignore - shouldn't be BLKI'ing.
 %ISIML::
	IFE INETP,JSR IMPLD4	; 2 Reading IMP leader (5 wds partial msg)
	IFN INETP,JSR IMPLD5	; 2 Reading IMP leader (4 wds partial msg)
 %ISINC::	JSR IMPRM4	; 3 Reading NCP control message (get all)
 %ISIND::	JSR IMPRM4	; 4 Reading NCP data (get all)
IFN INETP,[
 %ISINL::	JSR IMPLD4	; 5 Reading NCP IMP leader (partial msg)
 %ISIIL::	JSR IMPLD4	; 6 Reading IP IMP leader (partial msg)
 %ISIID::	JSR IMPRM4	; 7 Reading IP datagram (get all)
] ;INETP
	OFFSET 0

IMPRM3:	LDB B,IMBCBP	;BYTE COUNT OF EMPTY CONTROL LINK MESSAGE
	JUMPE B,IMPIRT
	AOS IMPNPE	;NO TEXT BUT BYTE COUNT NOT ZERO
	BUG INFO,[NCP: CTL MSG NO TXT, BC NOT 0. HST ],OCT,IMPHTN(H),[BC],DEC,B
	JRST IMPIRT

IFN INETP,[
EBLK		; PI 1 Input Done interrupt (from IMPILC+1, runout)
IMPLD5:	0	; JSR here on BLKI runout after reading 3rd wd of IMP leader.
BBLK		; Input Done is not set, because BLKI just turned it off.
	MOVEM A,IMPILC		; Save A
	MOVE A,[JSR IMPLD6]	; Make very next input word interrupt to IMPLD6
	EXCH A,IMPILC		; Do it, restore A
	JRST 12,@IMPLD5

EBLK		; PI 1 Input Done interrupt (from IMPILC)
IMPLD6:	0	; JSR here with 4th wd of leader in interface.
BBLK		; Must decide whether to continue reading leader in
		; 36-bit mode (NCP) or 32-bit mode (IP).
	MOVEM A,IMPILC		; Save A
	MOVE A,IMPILB+1		; Get word with link number in it
	ANDI A,377		; Mask off
	CAIN A,233		; Internet Protocol "link"?
	 JRST IMPLI3		; Yes!  Go handle it.

	; NCP read will immediately store current 36-bit word (4th),
	; store another 36-bit word (5th), and then run out to IMPLD4.
	MOVE A,[-2,,IMPILB+2]	; Reading NCP message.
	MOVEM A,IMBLKI
	MOVEI A,%ISINL		; Reading NCP leader, set state thereto.
	MOVEM A,IMPIS
	MOVE A,[JSR IMPLD4]	; And change dispatch vector.
	MOVEM A,IMPILC+1
	MOVE A,[BLKI IMP,IMBLKI]
	EXCH A,IMPILC		; Set up BLKI and restore A
	JRST 12,@IMPLD6	; Return.  Note current input word is still waiting.

	; IP read will immediately store current 36-bit word (4th),
	; then set up so next input-done interrupt (on 5th, 32-bit word)
	; goes directly to IMPIBZ->IMPLD2 with NETCHN PI.
	; (For AI-KA/MC/ML, perhaps by way of IMPIBK if output is active)
IMPLI3:	MOVEI A,%ISIIL		; Say reading IP type leader.
	MOVEM A,IMPIS
IFN KAIMP,CONO IMP,IMI32S+IMPCHN	; Set further input to 32-bit mode
IFN DMIMP,CONO FI,FII32S+NETCHN_3+IMPCHN
	DATAI IMP,IMPILB+3	; Store the 4th 36-bit word immediately; this
				; also starts interface reading the 5th word.
IFN KAIMP,[
	MOVE A,IMPLD6		; Now must set up for next interrupt.
	MOVEM A,IMPLD4		; Fake out the common code below
	JRST IMPLI4		; Set up for next Input-Done interrupt
]
IFN DMIMP,[
	MOVE A,[JSR IMPLD4]	; Shouldn't need this, but just in case...
	EXCH A,IMPILC		; Restore A, set int vector to safe rtn
	CONO FI,NETCHN*11	; DM interface can simply set Input-Done PIA!
	JRST 12,@IMPLD6
] ;DMIMP
] ;INETP

EBLK		; PI 1 Input Done interrupt (from IMPILC+1, runout)
IMPLD4:	0	; JSR here on BLKI runout after reading IMP leader
BBLK		; There is still one word to go, to be gotten at NETCHN level
IFN KAIMP,[
	MOVEM A,IMPILC		; Save A
				; Drop through to common code

IMPLI4:	SETZM IMPIH		; Say input no longer needs PI 1
	MOVEI A,NETCHN		; Make PI 2 (NETCHN) the exit PIA,
	SKIPL IMPOH		; unless output side needs PI 1.
	 MOVEM A,IMPPIA		; Set desired PIA channel on exit
	CONO IMP,@IMPPIA	; Set PIA to whatever it was!
	MOVE A,[JSR IMPIBK]	; Reset PI 1 Input-Done vector back to std.
	EXCH A,IMPILC		; and restore A.
];DMIMP
IFN DMIMP, CONO FI,NETCHN*11	; DM interface can simply set Input-Done PIA!
	JRST 12,@IMPLD4

IMPBCM: BUG INFO,[NCP: CTL MSG BS NOT 8 OR CT>120. HST ],OCT,IMPHTN(H),[BS ],DEC,IMPCBS,[BC ],DEC,IMPCBC
	JRST IMPIRT

;;; IMP->Host Type 6 - Host Down Status
;	H/ host index

IMPHDS:	MOVE A,IMPILB+1		;1.8-1.1 AND 4.9-4.2 ARE THE INFO
	MOVE B,IMPILB+2
	LSHC A,8
	ANDI A,177777
	HRRM A,IMPHTB(H)	;STORE, HOPE USER READ RFC 611
	JRST IMPIRT

;;; IMP->Host Type 1 - Error in leader (msg-id not given)
;;; IMP->Host Type 8 - Error in data  (msg-id given)

IMPBE1:	LDB T,IMSTBP	; Get subtype (4 bits)
	ANDI T,3	; Only 2 bits should be used
	AOS IMPM1S(T)	; Increment count of Type 1 subtype messages
IMPBE8:	MOVE T,TIME
	SUB T,LNETIM
	CAIL T,60.	;IGNORE ERROR DURING INITIAL SYNCHRONIZATION
	 BUG INFO,[IMP: Type ],DEC,A,[err msg, leader],OCT,IMPILB,OCT,IMPILB+1,OCT,IMPILB+2
IFN INETP,[
	MOVE B,IMPCLN
	CAIN B,233
	 AOS IMNIP8
]
	CAIN A,8.
	 JRST IMPBEB	; Process "Error in data" (decrement RFNM wait cnt)
	JRST IMPIRT

IMPBER:	SKIPGE IMPUP	;SKIP IF UP, OR THOUGHT TO BE BROKEN
	 JRST IMPBE2	;ALREADY DOWN, LET IT COME UP IN PEACE
	MOVSI J,SCLNET	;THINKS IT'S UP, RESET IT
	IORM J,SUPCOR
	CONI IMP,IMERCN	;RECORD IF IMP ERROR FLIP/FLOP SET
	SETOM IMPUP	;IMP IS DOWN
	SETZM IMPTCU	;AND NOT TRYING TO COME UP
IFN INETP,.ERR IP/TCP code needs handling for IMP crashing.
IFN NCPP,[
	MOVSI T,200000	;CLEAR ALL BUFFERS ACTIVE AT PI LEVEL
	MOVSI I,-IMPSTL	;SINCE CORE JOB MAY BE WAITING ON THIS
	ANDCAM T,IMSOC6(I)
	AOBJN I,.-1
] ;NCPP
IMPBE2:
IFN KAIMP,[
	SETZM IMPPIA
	CONO IMP,0
]
IFN DMIMP,CONO FI,FIRSET
	JRST IMPEX

;;; IMP->Host Type 2 - IMP going down

IMPGD:	LDB B,[060200,,IMPILB+1]	;WHY
	MOVEM B,IMPDWN
	LDB B,[020400,,IMPILB+1]	;HOW SOON GOING DOWN * 5 MINS
	MOVE H,B
	IMULI B,5*60.*30.	;TICKS IN 5 MINS
	ADD B,TIME
	MOVEM B,IMPDWN+1
	MOVE C,IMPILB+1		;HOW LONG TO BE DOWN, SPANS WORD BOUNDARY
	MOVE D,IMPILB+2
	LSHC C,8
	ANDI C,1777
	MOVE Q,C
	IMULI C,5*60.*30.
	ADD C,B			;ADD TO TIME DOWN
	MOVEM C,IMPDWN+2	;STORE TIME WHEN WILL BE UP
	IMULI H,5		;MINUTES
	IMULI Q,5
	BUG INFO,[IMP: Going down in ],DEC,H,[mins for ],DEC,Q,[mins, reason],DEC,IMPDWN
	JRST IMPIRT

;;; IMP Blockage avoidance
;	The current IMP software will not accept more than 8 active
; messages to a single host; attempting to send a 9th message will block
; ALL output to the interface, until the first message has been ack'd
; by means of one of the following message types:
;	Type 5, RFNM - Message delivered OK
;	Type 7, Host dead - transmit failed ("permanent")
;	Type 8, Error in data - interface spazzed
;	Type 9, Incomplete Transmission - temporary failure
; If for some reason the first message simply becomes lost, the IMP timeout
; (and blockage) can last for up to 30-45 seconds.
; More details in BBN Report 1822.
;	ITS attempts to fix this by keeping a count of active un-ACKed
; messages for each host it is communicating with.  A timeout is also
; associated with each host; if output to a given host is blocked by ITS
; because there are 8 active messages, trying to send a 9th message
; will check the last-RFNM-received time and if this was more than
; 30 or so seconds then the IMP is probably not giving us what it should
; and we should reset things for that host.

%IMPMA==:8.	; # of maximum active IMP messages allowed

; IMPBLI, IMPBLD - routines to hack active-message counts, called via JSP T,
;	IMPBLD decrements count.
;	IMPBLI increments count and skips if successful (else failed,
;		and must NOT output another message to this host!)
;		Also clobbers Q.
IMPBLI:	AOS Q,IMPHTC(H)
	CAIGE Q,%IMPMA	; Trying to send max or more messages?
	 JRST 1(T)	; No, can return safely.
	CAIG Q,8.	; Is this the maximum # allowed?
	 JRST [	MOVE Q,TIME		; Yes, set up blockage timeout
		ADDI Q,60.*30.		; for one minute.
		MOVEM Q,IMPHTT(H)
		JRST 1(T)]

	; Trying to send too many messages, block it (check for timeout though)
	SOS IMPHTC(H)	; Restore original count
	AOS IMNBLK	; Increment # of times softwarily blocked.
	MOVE Q,IMPHTT(H)
	CAML Q,TIME	; See if timeout still in the future
	 JRST (T)	; Yes, just take failure-return to block.
	BUG INFO,[IMP: RFNM-wait timeout! Hst=],OCT,IMPHTN(H)
	SETZM IMPHTC(H)	; This may be dangerous... oh well.
	SETZM IMPHTT(H)
	JRST (T)	; Block one last time, next try will win.

IMPBLD:	SOSL Q,IMPHTC(H)
	 JRST IMPBL2
	BUG INFO,[IMP: neg RFNM-wait cnt, Hst=],OCT,IMPHTN(H)
	SETZB Q,IMPHTC(H)
IMPBL2:	CAIL Q,8.-1	; If we were blocking on this host,
	 CALL IMPIOS	; Ensure IMP output started up so blocked stuff
	JRST (T)	; gets sent promptly.

;;; IMP->Host Type 8 - Error in Data
;	Actually this is secondary routine that IMPBE1 jumps to.

IMPBEB:	JSP T,IMPBLD	; Decrement count of active messages
	JRST IMPIRT



;;; IMP->Host Type 5 - RFNM (Ready For Next Message)

IFN INETP,.ERR INETP needs handling for RFNM on link 233
IMPRFN:
IFN BLIMPP,JSP T,IMPBLD	; Decrement count of active IMP messages for this host
	SKIPE IMPCLN	;LINK NUMBER
	 JRST IMRFN1	;DATA LINK
IMRFN6:	SKIPL IMPHTB(H)
	 JRST IMRFN7
	SKIPN IMPHTN(H)
	 BUG HALT,[IMP: IMRFN6 sees free IMPHTB entry ],OCT,H
	MOVSI D,400000
	ANDCAM D,IMPHTB(H)	;SET RFNM RECEIVED
	SOS IMRFCT
IFN NCPP,[
	SKIPL IMPNCQ		;SKIP IF NO PENDING CONTROL-LINK OUTPUT
	 PUSHJ P,IMPIOS		;START OUTPUT
];NCPP
	JRST IMPIRT

IMRFN7:	AOS IMNSRC
	BUG INFO,[IMP: Spurious RFNM from ],OCT,IMPHTN(H),[LNK 0]
	JRST IMPIRT

; RFNM on non-zero link message
IMRFN1:
IFN INETP,[
	MOVE A,IMPCLN	; Get link #
	CAIE A,233	; IP link number?
	 JRST IMRFNX	; No, skip IP code
	AOS IMNIPR	; Bump count of IP RFNMs received
	JRST IMPIRT	; and do nothing else about it, ugh.
IMRFNX:
];INETP
IFN NCPP,[
	MOVE A,IMPCSH
	LSH A,8
	IOR A,IMPCLN	;HEADER
	MOVSI I,-IMPSTL
	MOVEI W,1
IMRFN2:	LDB D,IMSCHL	;HEADER
	SKIPGE IMSOC1(I)	;SKIP IF SLOT NOT IN USE
	 CAME A,D	;SKIP IF HEADER AGREES
	  JRST IMRFN3
	HRRZ J,IMSOC4(I)	;STATE
	MOVEI W,0
	CAIN J,%NSRFN
	 SOJA J,IMRFN4	;RFNM WAIT
	MOVSI J,20000	;MIGHT BE EXPECTING RFNM AFTER CLOSE
	TDNE J,IMSOC5(I)
	 JRST [ ANDCAM J,IMSOC5(I)
		JRST IMPIRT ]
IMRFN3:	AOBJN I,IMRFN2
	BUG INFO,[IMP: Spurious RFNM from ],OCT,IMPHTN(H),[link],OCT,IMPCLN,SIXBIT,[(W)[SIXBIT/NOWAITNOLINK/]]
];NCPP
.ELSE	BUG INFO,[IMP: Spurious RFNM from ],OCT,IMPHTN(H),[link],OCT,IMPCLN
	AOS IMNSRF
	JRST IMPIRT

IFN NCPP,[
IMRFN4:	HRRM J,IMSOC4(I)	;CONNECTION OPEN
	MOVSI J,30000		;TURN OFF CLOSE-AWAITING-RFNM BIT, AND
	ANDCAM J,IMSOC5(I)	; RFNM-TIMEOUT-DURING-CLOSE BIT
	MOVE T,IMSPIP(I)
	CAME T,IMSMPP(I)	;SKIP IF OUTPUT BUFFER EMPTY
	 PUSHJ P,IMPIOS		;START OUTPUT
	JRST IMPIRT
];NCPP


;;; IMP->Host Type 9 - Incomplete Transmission

IMPINC:	LDB T,IMSTBP		; Get subtype field (4 bit reason for failure)
	AOS IMPM9S(T)		; Bump count of subtypes
	SKIPA E,[%NCINC]

;;; IMP->Host Type 7 - Destination Host Dead

IMPDHD:	 MOVEI E,%NCDED
IFN BLIMPP,JSP T,IMPBLD	; Decrement count of active IMP messages for this host
IFN INETP,[
	MOVE A,IMPCLN
	CAIN A,233
	 JRST [	CAIN E,%NCINC
		 AOS IMNIP9
		CAIN E,%NCDED
		 AOS IMNIP7
		JRST IMPIRT]	; Don't bother with NCP stuff or anything.
]
	MOVSI C,1000		;RST SENT?
	TDNE C,IMPHTB(H)
	 SOS IMRFCT		;GOING TO CLEAR IT, DECREASE TIMEOUT RQ
	MOVSI C,3000
	ANDCAM C,IMPHTB(H)	;CLEAR RST STATUS, RFNM SIMULATED LATER
IFN NCPP,[
	MOVSI I,-IMPSTL
IMDHD:	LDB T,IMSCFH
	SKIPGE C,IMSOC1(I)	;SKIP IF NOT IN USE
	 CAME T,IMPCSH
	  JRST IMDHDA
	HRRZ T,IMSOC4(I)
	TLNN C,200000	;THIS GUY IS CLOSING ANYWAY
	 CAIG T,%NSLSN
	  JRST IMDHDA	;THIS SOCKET'S HOST NUMBER FIELD IS MEANINGLESS
	CAIGE T,%NSCLI .SEE %NSINP
	 TDZA T,T .SEE %NSCLS
	  MOVEI T,%NSCLI
	HRRM T,IMSOC4(I)
	DPB E,IMSCLS	;CLS REASON
	PUSHJ P,IMPUIN
IMDHDA:	AOBJN I,IMDHD
];NCPP
	JRST IMRFN6	;CONTROL LINK, TAKE AS RFNM SO AS NOT TO HANG THINGS

IFN INETP,[
; IMPRMI - End of IP datagram, PI in progress on NETCHN, here from IMPBKX
;	A/ Last IMP word (32-bit)
;	TT/ CONI bits as of interrupt (note already returned to 36-bit mode)

IMPRMI:	AOS B,IMBLKI	; Get address to store last word in
	MOVEM A,(B)	; Store it away
	SUB B,IMPIBS	; Get # words read into datagram buffer
	MOVEI B,(B)
	MOVE A,IMPIDP	; Get pointer to IP datagram buffer we were using
	SETZ C,		; Say zero offset to IP header.
	MOVE J,IMPCSH	; Set index to host-table entry dgm received from.
	PUSHJ P,IPRDGM	; Call IP module to process received datagram at PI lvl
	SETZM IMPIDP	; Clear PI level pointer
	JRST IMPIR1	; Return from PI level, setting up for next msg

] ;INETP

SUBTTL	ARPANET OUTPUT INTERRUPT LEVEL

; See comments at IMPINT for a description of the overall IMP interrupt
; structure.  Output is simpler than input, however.
; Each IMP message is output at PI level 1 except for the initial DATAO;
; the setup and takedown for each message is done at PI level 2.
; The code on this page is not referenced by anything outside the page
; except interrupt vector setup at IMPINI (to IMPOBK) and IMOB9 (to IMPCH1).

; IMPCH1 - PI 1 Output-Done interrupt, from IMPOLC.
;	Comes here when last word DATAO'd has been sent to IMP.
EBLK
IMPCH1:	0
BBLK
	MOVEM A,IMPOLC		; Save A
	MOVE A,IMOPNT
IMCH1A:	SKIPGE A,IMOLST(A)	; Get next "instruction"
	 JRST IMCH1B		; Jump if it's a BLKO pointer
	CAILE A,3		; Ensure valid operation
	 JRST 4,.
	XCT IMCH1I(A)		; Do it
	AOS A,IMOPNT		; Still here?  Point to next operation
	JRST IMCH1A		; and loop to do it.

IMCH1I:	JRST IMCH1C		;0 Stop - end of output list
IFN KAIMP,CONO IMP,IMPLHW+IMPCHN	;1 Set Last Word
IFN DMIMP,CONO FI,FILHW+11*NETCHN
IFN KAIMP,CONO IMP,IMO32S+IMPCHN	;2 Set 32-bit mode
IFN DMIMP,CONO FI,FIO32S+10*NETCHN+IMPCHN
	JFCL			;3 NOP

IMCH1B:	MOVEM A,IMBLKO		; Set up BLKO - store the pointer
	MOVE A,[JSR IMCH1D]	; Set dispatch for BLKO runout
	MOVEM A,IMPOLC+1
	MOVE A,[BLKO IMP,IMBLKO]
	EXCH A,IMPOLC		; Store the BLKO and restore A
	AOS IMOPNT		; Increment output list ptr past this op.
	JRST 12,@IMPCH1		; Will interrupt immediately for first BLKO
				; word, since Output-Done wasn't cleared.

; PI 1 Output-Done, from IMPOLC+1 (BLKO runout)
;	Final word of the BLKO pointer is now in interface, being sent
;	to IMP, and Output-Done flag is off.
EBLK
IMCH1D:	0
BBLK
	MOVEM A,IMPOLC
	MOVE A,[JSR IMPCH1]	; Interrupt back when output of final word done
	EXCH A,IMPOLC
	JRST 12,@IMCH1D

; Here from IMPCH1, PI 1 Output-Done interrupt
;	Output list has hit "stop" operation (previous op had better be
;	1 to set Last-Host-Word!)
;	This code reverts control back to PI level 2 (IMPOBK).
IMCH1C:
IFN DMIMP,[
	CONO FI,FIOUT+11*NETCHN	; Reset PIA to normal 2
	MOVE A,[JSR RINT1]	; and ensure any further output PI 1 ints
]				; are classified as spurious.

IFN KAIMP,[			; Non-DM interface needs more hair.  
	SETZM IMPOH		; Say output side doesn't need PI 1 anymore
	MOVEI A,NETCHN		; And set exit PIA to 2,
	SKIPL IMPIH		; unless input side still needs PI 1
	 MOVEM A,IMPPIA		; Set it.
	CONO IMP,NETCHN		; Shouldn't this be CONO IMP,@IMPPIA??
	SETOM IMPO		; Tell IMPINT we have output-done interrupt.
	MOVE A,[JSR IMPOBK]	; Point PI 1 channel at switch-PIA routine,
]				; in case we interrupt on PI 1 again anyway.
	EXCH A,IMPOLC
	JRST 12,@IMPCH1

IFN KAIMP,[

; PI 1 Output Done interrupt, when we should really be interrupting
;	at IMPINT on PI 2.
EBLK
IMPOBK:	0
BBLK
	SETOM IMPO		; Tell IMPINT what kind of interrupt
	CONO IMP,NETCHN		; Reset PIA to 2
	JRST 12,@IMPOBK
]

; IMPOBZ - PI 2 (NETCHN) "Output Done" interrupt, via IMPINT.
;	Come here when we have finished sending stuff out at PI 1,
;	also when something wants output to start and tickled the "Done"
;	flag.
;	TT/ IMP CONI word.

IMPOBZ:	AOS IMCT3
IFN DMIMP,[
	TRC TT,IMPCHN_9	;CHECK IF OUTPUT PIA=IMPCHN
	TRNN TT,7_9
	 JRST IMPRET	;IGNORE, ALREADY HANDLED BY IMPCHN
]
	SKIPL B,IMPOS
	 CAIL B,IMPODL
	  JRST 4,.
	JRST @IMPODT(B)

IMPODT:	OFFSET -.
%ISODL::	IMPOB1	; 0 Idle, look for something to send
%ISONC::	IMPOB6	; 1 Finished NCP control message
%ISOND::	IMPOBG	; 2 Finished NCP data message
IFN INETP,%ISOID::IMPOBI	; 3 Finished IP datagram messge
IMPODL::OFFSET 0

IFE NCPP,[
IMPOB6:	SETZM IMPOS
	SKIPN A,IMPSVQ
	 JRST IMPRET		;THAT WAS A NOP
IMPOBG: JRST 4,.		;Can't get here
];not NCPP

; Idle - Look for output to send.  First ensure we can send stuff,
;	then try things in the order:
;	(1) Send NOP if net coming up
;	(2) Check NCP control queue, then (3) NCP data output queue
;	OR
;	(2) Check IP datagram queue
;
; Note that we alternate between checking the NCP and IP queues first,
; so that neither protocol can totally wedge the other up even if
; going at full blst.

IMPOB1:	HRRZ T,IMPUP
	CAIE T,-2	; Don't say it's up when it's still going down
	 CAIN T,1	; or when it is broken
	  JRST IMPOB9

	; First check to see if NOP needs to be sent.
	AOSG IMNOPC	; Check to see if sending NOPs
	 JRST IMONOP	; Output a NOP
	SETZM IMPUP	; Say IMP is up
	SETZM IMPTCU	; Say no longer trying to come up

	; Now see whether to check NCP or IP.
IFN INETP,[
	SETCMB T,IMPPSW	; Complement IMP output protocol switch
	JUMPN T,IMOBNN	; Jump for NCP
	PUSHJ P,IPGIOQ	; Check IP! Get IP IMP output queue entry if any
	 JRST IMOBN	; Nothing there, go check NCP.
	; Returns A/ ptr to IP dgm struct
	;	B/ BLKO pointer to 32-bit words
	;	C/ Arpanet address
	; The output list should be set up as:
	;IMOLST: -3,,IMOLDR
	;IMOMOD: 2		; switch to 32-bit mode
	;IMOBK1: -1,,IMOLDR+3	; Send 5th word of padding
	;IMOBK2:output BLKO	; Send datagram minus last word
	;	1
	;IMOBK3: -1,,lstwd-1	; BLKO to last word of datagram
	;	0
IMOBI1:
	MOVEM A,IMPODP	; Save ptr to datagram being output
	AOS IMNIPO	; # of IP datagrams sent
	ADD B,[1,,]	; Reduce BLKO count by one
	MOVEM B,IMOBK2	; Store in output list
	HLRO D,B	; Get -<# wds-1>
	MOVN D,D	; Get <#wds-1>
	ADDI D,(B)	; Get addr for last-word BLKO
	HRROM D,IMOBK3	; Store -1,,lastwd-1
	MOVE B,[-3,,IMOLDR]
	MOVEM B,IMOLST
	MOVE B,[-1,,IMOLDR+3]
	MOVEM B,IMOBK1

	; Output list set up, now must put together the IMP leader
	; in IMOLDR.
	MOVE B,[17_10.,,0]	; Regular message
	MOVEM B,IMOLDR
	LSH C,8.		; Move net address over
	IORI C,233		; Get link # for IP
	MOVEM C,IMOLDR+1	; Store 2nd word
	SETZM IMOLDR+2		; 3rd word can be zero
	SETZM IMOLDR+3		; rest is padding
	SETZM IMOLDR+4		; ditto

IFN KAIMP,CONO IMP,IMO32C
IFN DMIMP,CONO FI,FIO32C	;SET 36 BIT MODE FOR LEADER, CLEAR PIA
	DATAO IMP,IMOLDR	; Start it going!
	
	MOVEI C,%ISOID		; State = outputting IP datagram.
	JRST IMOB9

IMOBN:	SKIPE IMPPSW		; If no IP, check NCP only if havent already
	 JRST IMOBI9		; Skip NCP check, just return.
IMOBNN:
] ;INETP

IFN NCPP,[
	; Check NCP control message queue.
IFN BLIMPP,[
	MOVEI C,IMPNCQ
IMPOBV:	SKIPGE A,(C)
	 JRST IMPOBW
	HLRZ H,1(A)		; Got one!  Go send NCP control msg,
	SKIPL IMPHTB(H)		; unless control link waiting for RFNM
	 JSP T,IMPBLI		; or too many msgs active for that host.
	  CAIA
	   JRST [MOVEI T,(C) ? JRST IMPOB2]	; Compat hack
	MOVEI C,(A)
	JRST IMPOBV
] ;BLIMPP
.ELSE [
	MOVEI T,IMPNCQ
IMPOBV:	SKIPGE A,(T)
	 JRST IMPOBW
	HLRZ B,1(A)		;HOST TABLE INDEX
	SKIPL IMPHTB(B)		;SKIP IF WAITING FOR RFNM
	 JRST IMPOB2		; Got one!  Go send NCP control message.
	MOVE T,A
	JRST IMPOBV
] ;IFE BLIMPP

	; Check NCP data output queue.  This simply runs through
	; all the sockets to see if any want to output something.
IMPOBW:	MOVSI I,-IMPSTL
	MOVEI W,1
IMPOBB:	SKIPGE IMSOC1(I)	;SKIP IF NOT IN USE
	 TDNN W,IMSOC2(I)	;SKIP IF SEND
	  JRST IMOBA9
	HRRZ A,IMSOC4(I)
	CAIN A,%NSOPN		;SKIP IF WRONG STATE
	 SKIPGE IMSOC6(I)	;SKIP IF NOT LOCKED BY CORE JOB
IMOBA9:
IFE BLIMPP,IMPOBA:
	  AOBJN I,IMPOBB
IFN BLIMPP,[
	JUMPGE I,IMPOB9
	LDB H,IMSCFH		; Get fgn host index for this NCP conn
	JSP T,IMPBLI		; Make sure not too many active msgs
	 JRST IMOBA9		; Sigh, too many, keep looking.
	JRST IMPOBD		; OK, can send!
IMPOBA:	JSP T,IMPBLD		; Couldn't send data msg after all, decr cnt
	JRST IMOBA9
]
.ELSE	JUMPL I,IMPOBD		; Got one!  Go send NCP data message.
];NCPP

	; No more NCP output for IMP.
IMPOB9:
IFN INETP,[
	SKIPN IMPPSW	; If we didnt check IP queue yet,
	 JRST IMOBI9
	PUSHJ P,IPGIOQ	; then do it now, after NCP check.
	 JRST IMOBI9	; Nothing, really no more output.
	JRST IMOBI1	; Aha, have stuff!  Go get it.
IMOBI9:
]
	SETOM IMPOAC	; No more output, couldn't find anything to send.
IFN KAIMP,CONO IMP,IMPODC	; Clear Output-Done interrupt bit
IFN DMIMP,CONO FI,FIODC+NETCHN*11
	JRST IMPRET


; IMONOP - Send a NOP, here from IMPOBZ only.

IMONOP:	MOVEI A,IMPNOP-2
	SETZM IMPSVQ	; Set flag => this msg not really from control queue
	MOVEI B,1	; No text, but one extra wd (needed to make BLKO win)
	JRST IMPOB3

	; NOP Host-IMP leader
IMPNOP:	17_10.,,4_4	; New format, type 4 = NOP
	0
	5_10.,,0	; 5 16-bit words of padding desired

; IMPOB2 - Send a NCP control message, from IMPOBZ only

IMPOB2:	HRL A,T
	MOVEM A,IMPSVQ	;SAVE CTL MSG QUEUE PNTR
	HRRE B,1(A)	;GET COUNT 
	JUMPG B,IMPOB3
	 JRST 4,.	;ERROR, COUNT NOT > 0
IMPOB3:			; Entry pt from NOP sending code
IFN KAIMP,CONO IMP,IMO32C
IFN DMIMP,CONO FI,FIO32C	;SET 36 BIT MODE FOR LEADER, CLEAR PIA
	DATAO IMP,2(A)	;OUTPUT FIRST LEADER WORD
	MOVEI C,2(A)	;SET UP BLKO POINTER FOR REST OF LEADER
	SKIPN IMPSVQ
	 JRST [	HRLI C,-2	;KLUDGE, SENDING NOP
		JRST IMPOB4 ]
	HRLI C,-5
	AOS IMPMSS+0	;COUNT REGULAR MSGS SENT
IFN INETP,[
	MOVE T,IMPCLP		; HACK!  Get specified # to use for ctl link
	DPB T,[001000,,3(A)]	; Deposit in link field of leader.
];INETP
IFN NCPP,[
	LDB T,[341000,,10(A)]	;FIRST BYTE OF CONTROL MESSAGE
	CAIGE T,20
	 AOS IMPCMS(T)
];NCPP
IMPOB4:	MOVEM C,IMOLST	;STORE BLKO POINTER THAT SENDS LEADER
	MOVEI C,2	;DO TEXT WORDS IN 32-BIT MODE
	MOVEM C,IMOMOD
IFN DMIMP,MOVNI B,(B)	;GET MINUS WORD COUNT
IFN KAIMP,MOVNI B,-1(B)	;ALSO -1 FOR LAST WORD SENT SEPARATELY.
	HRLI B,7(A)	;ADDR-1 FOR BLKO
	MOVSM B,IMOBK1	;STORE FOR PI 1
IFN KAIMP,[
	MOVNI B,(B)
	ADD B,IMOBK1	;LAST WORD SENT SEPARATELY
	HRROM B,IMOBK3
	MOVEI B,3	;CHECK FOR SCREW CASE, ONLY SENDING ONE WORD, IT'S THE
	SKIPL IMOBK1	; LAST, SO NOP OUT THE MAIN BLKO
	 MOVEM B,IMOBK1
]
.ELSE	MOVEI B,3
	MOVEM B,IMOBK2	;NO 2ND BLKO
	MOVEI C,%ISONC	;STATE FOR CONTROL RETURN TO NETCHN
IMOB9:	MOVEM C,IMPOS
	SETZM IMOPNT
	MOVE C,[JSR IMPCH1]
	MOVEM C,IMPOLC
IFN KAIMP,[
	SETOM IMPOH	;OUTPUT SIDE WANTS IMP TO RUN ON CHANNEL 1
	MOVEI A,IMPCHN
	MOVEM A,IMPPIA
]
IFN DMIMP,CONO FI,FIOUT+NETCHN_3+IMPCHN	;SET PIA FOR OUTPUT
	JRST IMPRET

IFN INETP,[
; Here when IP datagram transmission completed

IMPOBI:	SETZM IMPOS	; Reset output state
	MOVE A,IMPODP
	PUSHJ P,IPIODN	; Tell IP level that datagram was output
	SETZM IMPODP
	JRST IMPRET
] ;INETP

SUBTTL	ARPANET CLOCK LEVEL

OVHMTR IMP	;NETWORK INTERRUPT LEVEL (NOT STYNET STUFF)

IMRSTO:	SKIPN IMRFCT	;CALLED AT 15 SEC CLK LEVEL TO UNHANG RFNM WAITS
IFE NCPP,POPJ P,
IFN NCPP,JRST IMFCT1
	MOVEI H,LIMPHT-1	;SOME CONTROL LINKS WAITING FOR RFNM, CHECK FOR TIME OUT
	MOVSI TT,401000	;4.9 AND 4.1 - RFNM AND RRP TIMEOUTS
	TDNN TT,IMPHTB(H)
IMRS4:	 SOJGE H,.-1
IFN NCPP,JUMPL H,IMFCT1
IFE NCPP,JUMPL H,CPOPJ
	CONO PI,NETOFF
	SKIPE IMPHTN(H)		;MAKE SURE IT'S A REAL HOST, NOT A FREE ENTRY
	 TDNN TT,IMPHTB(H)	;AND THAT THE BITS DIDN'T TURN OFF DUE TO INTERRUPT
	  JRST IMRS1
	LDB E,[221100,,IMPHTB(H)]
	LDB D,[051100,,TIME]	;GET TIME IN SECONDS (APPROX)
	CAMLE E,D
	 ADDI D,1_9
	SUB D,E
	CAIGE D,IMRFTO_<-5>
	 JRST IMRS1	;HASN'T TIMED OUT YET.
	LDB D,IMHSBT	;TIMED OUT.  CHECK RST/RRP STATUS.
	SOJE D,IMRS2
	MOVSI D,400000
	ANDCAM D,IMPHTB(H)	;RFNM SENT, CLEAR IT
	AOS IMNRFN
	SOS IMRFCT
	BUG INFO,[NET: CTL LNK RFNM TIMEOUT HST],OCT,IMPHTN(H)
IMRS1:	CONO PI,NETON
	JRST IMRS4

IMRS2:	DPB D,IMHSBT	;RST SENT, SET STATE TO DOWN
	BUG INFO,[NET: RST TIMEOUT HST=],OCT,IMPHTN(H)
	SOS IMRFCT
	JRST IMRS1

;NETHST (HOST INFO)
; ARG 1 - HOST => VAL 1 - STATUS, VAL 2 - HOST NUMBER
; ARG 1 - -1 => VAL 1 - (STATUS), VAL 2 - OUR HOST NUMBER
;NOT CURRENTLY IMPLEMENTED- ARG 1 - -1, ARG 2 - OUR GOING-DOWN REASON

ANETHST:HRRE T,A		;LET IMMEDIATE -1 WIN (777777 NOT A VALID HOST)
	AOJE T,ANETH2		;JUMP IF WANT LOCAL STATUS AND HOST NUMBER
	MOVE T,A
	JSP J,STDHST		;STANDARDIZE AND ERROR-CHECK HOST NUMBER
	MOVE B,T		;RETURN NEW FORMAT *******
	TLO B,(NW%ARP)
	MOVEI H,LIMPHT-1
	CONO PI,NETOFF		;DO WE HAVE STATUS?
	CAME T,IMPHTN(H)
	 SOJGE H,.-1
	JUMPGE H,ANETH1		;YES, RETURN IT
	CONO PI,NETON		;NO, HAVE TO GO GET IT
	MOVEM T,SRN3(U)
IFN NCPP,[
	PUSHJ P,NETO00		;GET IMSOC, RETURN WITH NETLST, IMSOC LOCKED
	 POPJ P,		;DEVICE FULL OR SOMETHING
	PUSHJ P,NETOR		;OPEN COMMUNICATIONS WITH HOST
	 JFCL			;IT'S DOWN, THAT'S OK
];NCPP
.ELSE	POPJ P,			;OH, TOO BAD
ANETH1:	MOVE A,IMPHTB(H)	;GET STATUS
	CONO PI,NETON
	EXCH A,B
	CALL CVH2NA		; Convert to HOSTS2 for compat
	EXCH A,B
	JRST LSWCJ1		;RETURN IMSOC, NETLST IF NOT DONE ALREADY

ANETH2:	;CAIL W,2		;(THIS IS A CROCK)
	 ;MOVEM B,NTHDSW	;IF 2 ARGS, SET OUR REASON FOR GOING DOWN.
	SKIPE IMPUP		;FAKE UP OUR STATUS
	 TDZA A,A		;WE'RE DOWN
	  MOVSI A,2000		;WE ARE UP
	MOVEI B,IMPUS		;AND OUR HOST #.
	JRST POPJ1


;NETIMP (REASON,TIMEDOWN,TIMEUP)  READ/SET

ANETIMP:JUMPLE W,ANETM1	;NO ARGS, RETURN
	CAIGE W,3	;MUST HAVE 3 ARGS IF ANY
	 JRST OPNL30
	MOVEM A,IMPDWN
	MOVEM B,IMPDWN+1
	MOVEM C,IMPDWN+2
	JRST POPJ1

ANETM1:	MOVE A,IMPDWN
	MOVE B,IMPDWN+1
	MOVE C,IMPDWN+2
	SKIPE IMPUP
	 TLO A,400000
	JRST POPJ1
